﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace WoWConnecter
{
    public class PacketCrypt
    {
        /// <summary>
        /// This is the key the client uses to encrypt its packets
        /// This is also the key the server uses to decrypt the packets
        /// </summary>
        private static readonly byte[] ServerDecryptionKey =
			{
				0xF4, 0x66, 0x31, 0x59, 0xFC, 0x83, 0x6E, 0x31,
				0x31, 0x02, 0x51, 0xD5, 0x44, 0x31, 0x67, 0x98
			};

        /// <summary>
        /// This is the key the client uses to decrypt server packets
        /// This is also the key the server uses to encrypt the packets
        /// </summary>
        private static readonly byte[] ServerEncryptionKey =
			{
				0x22, 0xBE, 0xE5, 0xCF, 0xBB, 0x07, 0x64, 0xD9,
				0x00, 0x45, 0x1B, 0xD0, 0x24, 0xB8, 0xD5, 0x45
			};

        // This is valid as HMAC-SHA1 transforms can be reused
        static readonly HMACSHA1 s_decryptServerDataHMAC = new HMACSHA1(ServerEncryptionKey);
        static readonly HMACSHA1 s_encryptClientDataHMAC = new HMACSHA1(ServerDecryptionKey);

        private readonly ARC4 decryptServerData;
        private readonly ARC4 encryptClientData;

        public PacketCrypt(byte[] sessionKey)
        {
            var encryptHash = s_encryptClientDataHMAC.ComputeHash(sessionKey);
            var decryptHash = s_decryptServerDataHMAC.ComputeHash(sessionKey);

            // Used by the client to decrypt packets sent by the server
            decryptServerData = new ARC4(decryptHash); // CLIENT-SIDE
            encryptClientData = new ARC4(encryptHash); // CLIENT-SIDE

            // Use the 2 encryption objects to generate a common starting point
            var syncBuffer = new byte[1024];
            encryptClientData.Process(syncBuffer, 0, syncBuffer.Length);

            // Use the 2 decryption objects to generate a common starting point
            syncBuffer = new byte[1024];
            decryptServerData.Process(syncBuffer, 0, syncBuffer.Length);
        }

        public void Decrypt(byte[] data, int start, int count)
        {
            decryptServerData.Process(data, start, count);
        }

        public void Encrypt(byte[] data, int start, int count)
        {
            encryptClientData.Process(data, start, count);
        }
    }
}
